package com.to8to.autotask.scheduler;

import it.sauronsoftware.cron4j.Scheduler;

import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Maps;
import com.to8to.autotask.util.Utils;
import com.to8to.commons.utils.StringUtil;
import com.to8to.es.util.LogUtil;

/**
 * AutoTaskScheduler.java
 * 作 者：atom.liu
 * 版 本：v2.0
 * 日 期：2014年12月1日
 * 描 述：自动任务调度执行器
 */
public class AutoTaskScheduler
{
    /**
     * cron4j 调度器
     */
    private static Scheduler scheduler = new Scheduler();

    /**
     * 已经启动的任务映射。key：任务名；value：TaskInfo
     */
    private static Map<String, TaskInfo> startedTaskMap = Maps.newHashMap();

    /**
     * 线程池
     */
    private static ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);

    private static final Logger logger = LoggerFactory.getLogger(AutoTaskScheduler.class);

    static
    {
        scheduler.addSchedulerListener(new AutoTaskSchedulerListener());
    }

    private AutoTaskScheduler()
    {
    }

    /**
     * 立刻执行提交的任务 
     */
    public static void executeNow(Runnable task)
    {
        if (task == null)
            return;
        pool.submit(task);
        logger.info(String.format("提交任务成功！任务 [ %s ] 将会立刻执行！", task));
    }

    /**
     * 在n小时之后执行
     */
    public static void executeAfterNHour(Runnable task, int hour)
    {
        if (task == null || hour <= 0)
            return;
        pool.schedule(task, hour, TimeUnit.HOURS);
        logger.info(String.format("提交任务成功！任务 [ %s ] 在 [ %s ] 小时之后执行！", task, hour));
    }

    /**
     * 添加调度任务
     */
    public static void addSchedulerTask(Map<String, String> map)
    {
        if (Utils.isNullOrEmpty(map))
            return;

        Set<String> newTasks = map.keySet();
        Set<String> startedTasks = startedTaskMap.keySet();
        //删除已经配置文件中已经不存在的定时任务
        for (String startedTask : startedTasks)
        {
            if (!newTasks.contains(startedTask))
            {
                scheduler.deschedule(startedTaskMap.get(startedTask).getTaskId());
                startedTaskMap.remove(startedTask);
            }
        }

        //启动或重新设置定时任务的执行时间
        for (String newTask : newTasks)
        {
            String newTaskPattern = map.get(newTask);
            if (StringUtil.isEmpty(newTaskPattern))
                continue;
            if (startedTasks.contains(newTask))
            {
                TaskInfo startedTaskInfo = startedTaskMap.get(newTask);
                //如果SchedulerPattern没有改变，则不重新设置
                if (newTaskPattern.trim().equals(startedTaskInfo.getSchedulerPatten().trim()))
                    continue;
                startedTaskInfo.setSchedulerPatter(newTaskPattern);
                scheduler.reschedule(startedTaskInfo.getTaskId(), newTaskPattern);
            }
            else
            {
                try
                {
                    Object obj = Class.forName(newTask).newInstance();
                    String taskId = scheduler.schedule(newTaskPattern, (Runnable) obj);
                    startedTaskMap.put(newTask, new TaskInfo(taskId, newTaskPattern));
                }
                catch (Exception e)
                {
                    logger.error("Class.forName(%).newInstance() Error！{} \n {}", e, LogUtil.logStackTrace(e));
                }
            }
        }

        StringBuilder logSB = new StringBuilder("当前Scheduler的任务：\r\n");
        for (Entry<String, TaskInfo> entry : startedTaskMap.entrySet())
            logSB.append(entry.getKey()).append(": ").append(entry.getValue().getSchedulerPatten()).append("\r\n");
        logger.info(logSB.toString());
    }

    /**
     * 结束任务调度
     */
    public static void stop()
    {
        if (scheduler.isStarted())
        {
            scheduler.stop();
            logger.info(String.format("AutoTaskScheduler自动调度任务停止%s！", scheduler.isStarted() ? "失败" : "成功"));
        }
    }

    /**
     * 启动任务调度
     */
    public static void start()
    {
        if (scheduler.isStarted())
            throw new IllegalStateException("AutoTaskScheduler already started");

        scheduler.start();
        logger.info("AutoTaskScheduler自动任务调度启动成功！");
    }

    private static class TaskInfo
    {
        private String taskId;

        private String schedulerPatten;

        public TaskInfo(String taskId, String schedulerPatten)
        {
            this.taskId = taskId;
            this.schedulerPatten = schedulerPatten;
        }

        @Override
        public String toString()
        {
            return String.format("%s[ %s ]", schedulerPatten, taskId);
        }

        public String getTaskId()
        {
            return taskId;
        }

        @SuppressWarnings("unused")
        public void setTaskId(String taskId)
        {
            this.taskId = taskId;
        }

        public String getSchedulerPatten()
        {
            return schedulerPatten;
        }

        public void setSchedulerPatter(String schedulerPatten)
        {
            this.schedulerPatten = schedulerPatten;
        }
    }
}
